#define _GNU_SOURCE
#include <stdio.h>
#include <cJSON.h>
#include "parser.h"

typedef struct OptcParser {
    #define LINE_SIZE (1024*1024)
    Parser *base;
    char line[LINE_SIZE];
    GQueue *queued_events;
}OptcParser;


static int
optc_parser_parse (void *opaque, FILE *in, Event *e) {
    size_t len;
    ssize_t nread;
    OptcParser * p = opaque;
    cJSON * json;
    char *src_ip, *dest_ip, *src_port, *dest_port, *image_path, *image_name, *direction, *file_path, *new_path, 
             *module_path, *parent_image_path, *parent_image_name, *key, *logon_id;
            src_ip = dest_ip = src_port = dest_port = image_path = image_name = direction = file_path = 
            new_path = module_path = parent_image_path = parent_image_name = key = logon_id = "";
    if (p->queued_events->length != 0) {
        Event *tmp_e = g_queue_pop_head (p->queued_events);
        event_copy (tmp_e, e);
        event_destructor (tmp_e);
        goto incoming;
    }
    json = NULL;
    again:
    if (json != NULL) {
        fprintf (stderr, "%s", p->line);
        cJSON_Delete (json);
        json = NULL;
    }
    if (fgets (p->line, LINE_SIZE, in) != NULL) {
        json = cJSON_Parse (p->line);
        if (json == NULL) {
            json = (void*)-1;
            goto again;
        }
        cJSON *action = cJSON_GetObjectItem (json, "action");
        cJSON *host = cJSON_GetObjectItem (json, "hostname");
        cJSON *pid = cJSON_GetObjectItem (json, "pid");
        cJSON *ppid = cJSON_GetObjectItem (json, "ppid");
        cJSON *properties = cJSON_GetObjectItem (json, "properties");
        if (action == NULL || host==NULL || pid==NULL || ppid == NULL || properties == NULL)
            goto again;
        cJSON *tmp;
        GRegex *rx;
        GMatchInfo *match_info;
        if (!strcmp (action->valuestring, "START")) {
            tmp = cJSON_GetObjectItem(properties, "src_ip");
            if (tmp != NULL) {
                src_ip = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "dest_ip");
            if (tmp != NULL) {
                dest_ip = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "src_port");
            if (tmp != NULL) {
                src_port = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "dest_port");
            if (tmp != NULL) {
                dest_port = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "direction");
            if (tmp != NULL) {
                direction = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char port_str[EVENT_STR_BUFSZ];
            //g_snprintf (port_str, EVENT_STR_BUFSZ, "%s:%s",dest_ip, dest_port);
            //event_populate (e, host->valuestring, "Connect", port_str, "Port",proc_str, "Process");
            //Event *next_e = event_create ();
            if (!g_strcmp0 (direction, "inbound")) {
                g_snprintf (port_str, EVENT_STR_BUFSZ, "%s:%s",dest_ip, dest_port);
                event_populate (e, host->valuestring, "Listening",   port_str, "Port",proc_str, "Process");
            } else {
                g_snprintf (port_str, EVENT_STR_BUFSZ, "%s:%s",src_ip, src_port);
                event_populate (e, host->valuestring, "Listening",   port_str, "Port",proc_str, "Process");
            }
            
            //g_queue_push_tail (p->queued_events, next_e);
        } else if (!strcmp (action->valuestring, "MESSAGE")) {
            tmp = cJSON_GetObjectItem(properties, "src_ip");
            if (tmp != NULL) {
                src_ip = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "dest_ip");
            if (tmp != NULL) {
                dest_ip = tmp->valuestring;
            }else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "src_port");
            if (tmp != NULL) {
                src_port = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "dest_port");
            if (tmp != NULL) {
                dest_port = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "direction");
            if (tmp != NULL) {
                direction = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char port_str[EVENT_STR_BUFSZ];
            g_snprintf (port_str, EVENT_STR_BUFSZ, "%s:%s",dest_ip, dest_port);
            Event *next_e = event_create ();
            if (!strcmp (direction, "inbound")) {
                g_snprintf (port_str, EVENT_STR_BUFSZ, "%s:%s",src_ip, src_port);
                event_populate (e, host->valuestring, "Receive", port_str, "Port", proc_str, "Process");
                g_snprintf (port_str, EVENT_STR_BUFSZ, "%s:%s",dest_ip, dest_port);
                event_populate (next_e, host->valuestring, "Listening",   port_str, "Port",proc_str, "Process");
                g_queue_push_tail (p->queued_events, next_e);
            } else {
                g_snprintf (port_str, EVENT_STR_BUFSZ, "%s:%s",dest_ip, dest_port);
                event_populate (e, host->valuestring, "Send", proc_str, "Process", port_str, "Port");
                g_snprintf (port_str, EVENT_STR_BUFSZ, "%s:%s",src_ip, src_port);
                event_populate (next_e, host->valuestring, "Listening",   port_str, "Port",proc_str, "Process");
                g_queue_push_tail (p->queued_events, next_e);
            }
        } else if (!strcmp (action->valuestring, "CREATE")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "file_path");
            if (tmp != NULL) {
                file_path = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            } 
            g_regex_unref (rx); 
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char file_str[EVENT_STR_BUFSZ];
            g_snprintf (file_str, EVENT_STR_BUFSZ, "%s", file_path);
            event_populate (e, host->valuestring, "Create", proc_str, "Process", file_str, "File");
        } else if (!strcmp (action->valuestring, "RENAME")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "file_path");
            if (tmp != NULL) {
                file_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "new_path");
            if (tmp != NULL) {
                new_path = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char file_str[EVENT_STR_BUFSZ];
            g_snprintf (file_str, EVENT_STR_BUFSZ, "%s", file_path);
            char new_file_str[EVENT_STR_BUFSZ];
            g_snprintf (new_file_str, EVENT_STR_BUFSZ, "%s", new_path);
            event_populate (e, host->valuestring, "Rename", proc_str, "Process", file_str, "File");
            Event *next_e = event_create ();
            event_populate (next_e, host->valuestring, "CopyTo",   file_str, "File", new_file_str, "File");
            g_queue_push_tail (p->queued_events, next_e);
        } else if (!strcmp (action->valuestring, "EDIT")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "key");
            if (tmp != NULL) {
                key = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char key_str[EVENT_STR_BUFSZ];
            g_snprintf (key_str, EVENT_STR_BUFSZ, "%s", key);
            event_populate (e, host->valuestring, "Edit", proc_str, "Process", key_str, "Key");
        } else if (!strcmp (action->valuestring, "ADD")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "key");
            if (tmp != NULL) {
                key = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char key_str[EVENT_STR_BUFSZ];
            g_snprintf (key_str, EVENT_STR_BUFSZ, "%s", key);
            event_populate (e, host->valuestring, "Add", proc_str, "Process", key_str, "Key");
        } else if (!strcmp (action->valuestring, "REMOVE")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "key");
            if (tmp != NULL) {
                key = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char key_str[EVENT_STR_BUFSZ];
            g_snprintf (key_str, EVENT_STR_BUFSZ, "%s", key);
            event_populate (e, host->valuestring, "Remove", proc_str, "Process", key_str, "Key");
        } else if (!strcmp (action->valuestring, "WRITE")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "file_path");
            if (tmp != NULL) {
                file_path = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char file_str[EVENT_STR_BUFSZ];
            g_snprintf (file_str, EVENT_STR_BUFSZ, "%s", file_path);
            event_populate (e, host->valuestring, "Write", proc_str, "Process", file_str, "File");
        } else if (!strcmp (action->valuestring, "LOGIN")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "logon_id");
            if (tmp != NULL) {
                logon_id = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char login_str[EVENT_STR_BUFSZ];
            g_snprintf (login_str, EVENT_STR_BUFSZ, "%s", logon_id);
            event_populate (e, host->valuestring, "Login", proc_str, "Process", login_str, "User");
        } else if (!strcmp (action->valuestring, "INTERACTIVE")) {
            char *req_logon_id = NULL;
            // tmp = cJSON_GetObjectItem(properties, "image_path");
            // if (tmp != NULL) {
            //     image_path = tmp->valuestring;
            // }
            tmp = cJSON_GetObjectItem(properties, "logon_id");
            if (tmp != NULL) {
                logon_id = tmp->valuestring;
            } else {
                goto again;
            }
             tmp = cJSON_GetObjectItem(properties, "requesting_logon_id");
            if (tmp != NULL) {
                req_logon_id = tmp->valuestring;
            } else {
                goto again;
            }
            //guint pid_u = pid->valueint;
            // image_name = NULL;
            // rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            // if (g_regex_match (rx, image_path, 0, &match_info)) {
            //     image_name = g_match_info_fetch (match_info, 0);
            //     g_match_info_free (match_info);
            // }
            // g_regex_unref (rx);
            //char *proc_str = g_strdup_printf ("%s:%u",image_name,pid_u);
            char logon_str[EVENT_STR_BUFSZ];
            g_snprintf (logon_str, EVENT_STR_BUFSZ, "%s", logon_id);
            char req_logon_str[EVENT_STR_BUFSZ];
            g_snprintf (req_logon_str, EVENT_STR_BUFSZ, "%s", logon_id);
            event_populate (e, host->valuestring, "Interactive", logon_str, "User", req_logon_id, "User");
            //g_free (proc_str);
        } else if (!strcmp (action->valuestring, "UNLOCK")) {
            char *req_logon_id = NULL;
            // tmp = cJSON_GetObjectItem(properties, "image_path");
            // if (tmp != NULL) {
            //     image_path = tmp->valuestring;
            // }
            tmp = cJSON_GetObjectItem(properties, "logon_id");
            if (tmp != NULL) {
                logon_id = tmp->valuestring;
            } else {
                goto again;
            }
             tmp = cJSON_GetObjectItem(properties, "requesting_logon_id");
            if (tmp != NULL) {
                req_logon_id = tmp->valuestring;
            } else {
                goto again;
            }
            //guint pid_u = pid->valueint;
            // image_name = NULL;
            // rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            // if (g_regex_match (rx, image_path, 0, &match_info)) {
            //     image_name = g_match_info_fetch (match_info, 0);
            //     g_match_info_free (match_info);
            // }
            // g_regex_unref (rx);
            //char *proc_str = g_strdup_printf ("%s:%u",image_name,pid_u);
            char logon_str[EVENT_STR_BUFSZ];
            g_snprintf (logon_str, EVENT_STR_BUFSZ, "%s", logon_id);
            char req_logon_str[EVENT_STR_BUFSZ];
            g_snprintf (req_logon_str, EVENT_STR_BUFSZ, "%s", logon_id);
            event_populate (e, host->valuestring, "Unlock", logon_str, "User", req_logon_id, "User");
            //g_free (proc_str);
        } else if (!strcmp (action->valuestring, "REMOTE")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "logon_id");
            if (tmp != NULL) {
                logon_id = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char login_str[EVENT_STR_BUFSZ];
            g_snprintf (login_str, EVENT_STR_BUFSZ, "%s", logon_id);
            event_populate (e, host->valuestring, "Remote", proc_str, "Process", login_str, "User");
        } else if (!strcmp (action->valuestring, "LOGOUT")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "logon_id");
            if (tmp != NULL) {
                logon_id = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char login_str[EVENT_STR_BUFSZ];
            g_snprintf (login_str, EVENT_STR_BUFSZ, "%s", logon_id);
            event_populate (e, host->valuestring, "Logout", proc_str, "Process", login_str, "User");
        } else if (!strcmp (action->valuestring, "GRANT")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "logon_id");
            if (tmp != NULL) {
                logon_id = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char login_str[EVENT_STR_BUFSZ];
            g_snprintf (login_str, EVENT_STR_BUFSZ, "%s", logon_id);
            event_populate (e, host->valuestring, "Grant", proc_str, "Process", login_str, "User");
        } else if (!strcmp (action->valuestring, "DELETE")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "file_path");
            if (tmp != NULL) {
                file_path = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char file_str[EVENT_STR_BUFSZ];
            g_snprintf (file_str, EVENT_STR_BUFSZ, "%s", file_path);
            event_populate (e, host->valuestring, "Delete", proc_str, "Process", file_str, "File");
        } else if (!strcmp (action->valuestring, "READ")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "file_path");
            if (tmp != NULL) {
                file_path = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char file_str[EVENT_STR_BUFSZ];
            g_snprintf (file_str, EVENT_STR_BUFSZ, "%s", file_path);
            event_populate (e, host->valuestring, "Read", file_str, "File", proc_str, "Process");
            
        } else if (!strcmp (action->valuestring, "MODIFY")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "file_path");
            if (tmp != NULL) {
                file_path = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char file_str[EVENT_STR_BUFSZ];
            g_snprintf (file_str, EVENT_STR_BUFSZ, "%s", file_path);
            event_populate (e, host->valuestring, "Modify",proc_str, "Process", file_str, "File");
        } else if (!strcmp (action->valuestring, "LOAD")) {
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "module_path");
            if (tmp != NULL) {
                module_path = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char module_str[EVENT_STR_BUFSZ];
            g_snprintf (module_str, EVENT_STR_BUFSZ, "%s", module_path);
            event_populate (e, host->valuestring, "Load",module_str, "Module", proc_str, "Process");
        } else if (!strcmp (action->valuestring, "TERMINATE")) {
            char* tgt_pid = NULL;
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "tgt_pid");
            if (tmp != NULL) {
                tgt_pid = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL; 
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char tgt_proc_str[EVENT_STR_BUFSZ];
            g_snprintf (tgt_proc_str, EVENT_STR_BUFSZ, "(null):%s", tgt_pid);
            event_populate (e, host->valuestring, "Terminate", proc_str, "Process", tgt_proc_str, "Process");
            // e->remove_target = TRUE;
        } else if (!strcmp (action->valuestring, "OPEN")) {
            char* tgt_pid = NULL;
             tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "parent_image_path");
            if (tmp != NULL) {
                parent_image_path = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            guint ppid_u = ppid->valueint;
            image_name = NULL; 
            parent_image_name = NULL;
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, parent_image_path, 0, &match_info)) {
                parent_image_path = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char parent_proc_str[EVENT_STR_BUFSZ];
            g_snprintf (parent_proc_str, EVENT_STR_BUFSZ, "%s:%u",parent_image_name,ppid_u);
            event_populate (e, host->valuestring, "Open",  parent_proc_str, "Process", proc_str, "Process");
        } else if (!strcmp (action->valuestring, "REMOTE_CREATE")) {
            char* tgt_pid = NULL;
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "tgt_pid");
            if (tmp != NULL) {
                tgt_pid = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL; 
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char tgt_proc_str[EVENT_STR_BUFSZ];
            g_snprintf (tgt_proc_str, EVENT_STR_BUFSZ, "(null):%s",tgt_pid);
            event_populate (e, host->valuestring, "RemoteCreate", proc_str, "Process", tgt_proc_str, "Process");
        } else if (!strcmp (action->valuestring, "COMMAND")) {
            char* shell = NULL;
            tmp = cJSON_GetObjectItem(properties, "image_path");
            if (tmp != NULL) {
                image_path = tmp->valuestring;
            } else {
                goto again;
            }
            tmp = cJSON_GetObjectItem(properties, "payload");
            if (tmp != NULL) {
                shell = tmp->valuestring;
            } else {
                goto again;
            }
            guint pid_u = pid->valueint;
            image_name = NULL; 
            rx = g_regex_new ("[^\\\\]*$", G_REGEX_DEFAULT,  G_REGEX_MATCH_DEFAULT, NULL);
            if (g_regex_match (rx, image_path, 0, &match_info)) {
                image_name = g_match_info_fetch (match_info, 0);
                g_match_info_free (match_info);
            }
            g_regex_unref (rx);
            char proc_str[EVENT_STR_BUFSZ];
            g_snprintf (proc_str, EVENT_STR_BUFSZ,"%s:%u",image_name,pid_u);
            char shell_str[EVENT_STR_BUFSZ];
            g_snprintf (shell_str, EVENT_STR_BUFSZ, "%s",shell);
            event_populate (e, host->valuestring, "Command", proc_str, "Process", shell_str, "Shell");
        } else {
            fprintf (stderr, "%s routine undefined.\n", action->valuestring);
            // cJSON_Delete (json);
            goto again;
        }
        cJSON_Delete (json);
    } else {
        return PARSER_END;
    }
    incoming:
    return PARSER_INCOMING;
}

void
optc_parser_destory (void *opaque) {
    OptcParser *optc_p = opaque;
    g_queue_free (optc_p->queued_events);
    g_free (optc_p);
}

Parser *
optc_parser_create (FILE *in) {
    OptcParser *optc_p;
    Parser *p;
    optc_p = g_new0 (OptcParser, 1);
    if (!optc_p) return NULL;
    optc_p->queued_events = g_queue_new ();
    p = parser_create (optc_p, optc_parser_destory, in);
    if (!p) {
        g_free (optc_p);
        return NULL;
    }
    p->parse = optc_parser_parse;
    optc_p->base = p;
    return p;
}